package com.ship.core.processor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.mvc.method.annotation.JsonViewRequestBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义转换器
 */
public class DecryptEncryptFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter4 implements InitializingBean {

    private RequestDecryptResponseEncryptBodyProcessor requestDecryptResponseEncryptBodyProcessor;

    @Autowired
    private GsonHttpMessageConverter gsonHttpMessageConverter;

    public DecryptEncryptFastJsonHttpMessageConverter(RequestDecryptResponseEncryptBodyProcessor requestDecryptResponseEncryptBodyProcessor) {
        this.requestDecryptResponseEncryptBodyProcessor = requestDecryptResponseEncryptBodyProcessor;
    }

    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {

        InputStream in = inputMessage.getBody();
        FastJsonConfig fastJsonConfig = getFastJsonConfig();

        if (requestDecryptResponseEncryptBodyProcessor != null) {
            String input = requestDecryptResponseEncryptBodyProcessor.decryptRequestBody(inputMessage, fastJsonConfig.getCharset());

            byte[] bytes = input.getBytes(fastJsonConfig.getCharset());
            return JSON.parseObject(bytes, 0, bytes.length, fastJsonConfig.getCharset(), type, fastJsonConfig.getFeatures());
        }
        return JSON.parseObject(in, fastJsonConfig.getCharset(), type, fastJsonConfig.getFeatures());

    }

    @Override
    protected void writeInternal(Object obj, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        HttpHeaders headers = outputMessage.getHeaders();
        ByteArrayOutputStream outnew = new ByteArrayOutputStream();
        FastJsonConfig fastJsonConfig = getFastJsonConfig();

        if (requestDecryptResponseEncryptBodyProcessor != null) {
            String jsonString = JSON.toJSONString(obj,
                    fastJsonConfig.getSerializeConfig(),
                    fastJsonConfig.getSerializeFilters(),
                    fastJsonConfig.getDateFormat(),
                    JSON.DEFAULT_GENERATE_FEATURE, //
                    fastJsonConfig.getSerializerFeatures());
            obj = requestDecryptResponseEncryptBodyProcessor.encryptResponseBody(jsonString, headers, fastJsonConfig.getCharset());
        }

        int len = JSON.writeJSONString(outnew, //
                fastJsonConfig.getCharset(), //
                obj, //
                fastJsonConfig.getSerializeConfig(), //
                fastJsonConfig.getSerializeFilters(), //
                fastJsonConfig.getDateFormat(), //
                JSON.DEFAULT_GENERATE_FEATURE, //
                fastJsonConfig.getSerializerFeatures());
        headers.setContentLength(len);
        OutputStream out = outputMessage.getBody();
        outnew.writeTo(out);
        outnew.close();


    }

    @Override
    protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {

        InputStream in = inputMessage.getBody();
        FastJsonConfig fastJsonConfig = getFastJsonConfig();


        if (requestDecryptResponseEncryptBodyProcessor != null) {
            String input = requestDecryptResponseEncryptBodyProcessor.decryptRequestBody(inputMessage, fastJsonConfig.getCharset());
            return JSON.parseObject(input.getBytes(fastJsonConfig.getCharset()), 0, input.length(), fastJsonConfig.getCharset(), clazz, fastJsonConfig.getFeatures());
        }
        return JSON.parseObject(in, fastJsonConfig.getCharset(), clazz, fastJsonConfig.getFeatures());


    }

    @Resource
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;



    @Override
    public void afterPropertiesSet() throws Exception {
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(requestMappingHandlerAdapter.getReturnValueHandlers());
        int index = 0;
        RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = null;
        for (int i = 0, length = handlers.size(); i < length; i++) {
            HandlerMethodReturnValueHandler handlerMethodReturnValueHandler = handlers.get(i);
            if (handlerMethodReturnValueHandler instanceof org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor) {
                List<HttpMessageConverter<?>> converters = new ArrayList<>();
                converters.add(this);
                converters.add(gsonHttpMessageConverter);
                ContentNegotiationManager manager = new ContentNegotiationManager();
                List<Object> list = new ArrayList<>();
                list.add(new JsonViewRequestBodyAdvice());
                list.add(new JsonViewResponseBodyAdvice());
                requestResponseBodyMethodProcessor = new RequestResponseBodyMethodProcessor(converters,manager,list);
                index = i;
            }
        }
        handlers.remove(index);
        handlers.add(index, requestResponseBodyMethodProcessor);
        requestMappingHandlerAdapter.setReturnValueHandlers(handlers);


        int requestDecryptResponseEncryptBodyMethodProcessorIndex = 0;
        List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(requestMappingHandlerAdapter.getArgumentResolvers());
        RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor2 = null;
        for (int i = 0, length = argumentResolvers.size(); i < length; i++) {
            HandlerMethodArgumentResolver argumentResolver = argumentResolvers.get(i);
            if (argumentResolver instanceof org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor) {
                List<HttpMessageConverter<?>> converters = new ArrayList<>();
                converters.add(this);
                converters.add(gsonHttpMessageConverter);
                ContentNegotiationManager manager = new ContentNegotiationManager();
                List<Object> list = new ArrayList<>();
                list.add(new JsonViewRequestBodyAdvice());
                list.add(new JsonViewResponseBodyAdvice());
                requestResponseBodyMethodProcessor2 = new RequestResponseBodyMethodProcessor(converters,manager,list);
                requestDecryptResponseEncryptBodyMethodProcessorIndex = i;
            }
        }
        argumentResolvers.remove(requestDecryptResponseEncryptBodyMethodProcessorIndex);
        argumentResolvers.add(requestDecryptResponseEncryptBodyMethodProcessorIndex, requestResponseBodyMethodProcessor2);
        requestMappingHandlerAdapter.setArgumentResolvers(argumentResolvers);


    }
}
